home *** CD-ROM | disk | FTP | other *** search
- /*
- File: ModemDriver.c
-
- Contains: Code for USB Modem driver
-
- Version: xxx put version here xxx
-
- Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
-
- */
- #include <DriverServices.h>
-
- #include "Modem.h"
- #include "ModemDriver.h"
- #include "ShimSerialHAL.h"
-
- static serPB gSerialGlobals;
- static USBPB syncPB, interruptPB, readPB, writePB, stallPB, delayPB;
-
- /************************************************************************************/
- //
- // immediateError
- //
- // Determines whether it's an error or just pending.
- //
- /************************************************************************************/
-
- static Boolean immediateError(OSStatus err)
- {
- return ((err != kUSBPending) && (err != noErr));
- }
-
- /************************************************************************************/
- //
- // ConfigurationHandler
- //
- // Configures the USB Serial Device (Modem).
- //
- /************************************************************************************/
-
- static void ConfigurationHandler(USBPB *pb)
- {
- serPB *sp = &gSerialGlobals;
- USBEndPointDescriptor *eDesc;
- OSStatus err;
-
- TraceMessage(0, "\pEntering ConfigurationHandler");
-
- if(pb->usbStatus != noErr)
- {
- if((sp->onError == kReset) && (sp->retries > 0))
- {
- /* no idea what to do now?? */
- USBExpertFatalError(sp->deviceRef, pb->usbStatus, sp->errorString, pb->usbRefcon);
-
- /* Mark port as errored */
- }
- else
- {
- StatusMessage(sp->deviceRef, sp->errorString, pb->usbStatus);
- pb->usbRefcon = sp->onError;
-
- USBClearPipeStallByReference(pb->usbReference);
-
- /* we'll delay coming back to here */
- sp->retries--;
-
- pb->usbReqCount = 0;
- /* pb->usbFlags = kUSBtaskTime */
- USBDelay(pb);
-
- }
-
- return;
- }
-
- sp->onError = kReset;
-
- do{switch(pb->usbRefcon++)
- {
- case kStartConfig:
- noteError("\pModem Driver driver does not recognize device (we'll try to config. it anyway)");
- if(sp->deviceDescriptor->numConf != 2)
- {
- StatusMessage(sp->deviceRef, sp->errorString, 0);
- // break; /* Now what ?? */
- }
-
- /* Configure device to single configuration */
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBNone, kUSBStandard, kUSBDevice);
-
- pb->usb.cntl.BRequest = kUSBRqSetConfig;
- pb->usb.cntl.WValue = 2; /* select config #2 - seems config 1 is Win95 specific */
- pb->usb.cntl.WIndex = 0;
- pb->usbReqCount = 0;
- pb->usbBuffer = nil;
- sp->onError = 1;
-
- noteError("\pModem driver Setting Config");
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
- break;
-
- case kGetConfig:
- /* get the full config descriptor */
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.WValue = 1;
- if (sp->retries > 0)
- {
- sp->onError = kGetConfig;
- } else {
- sp->onError = kReset;
- }
- noteError("\pModem driver getting full config descriptor");
- if(immediateError(err = USBGetFullConfigurationDescriptor(pb)))
- {
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- break;
-
- case kGetDataInterface:
- /* remember the full config descriptor */
- sp->conf = pb->usbBuffer;
- StatusMessage(sp->deviceRef, "\pConfiguration Descriptor - ", (unsigned long)sp->conf);
-
- /* find the interface */
- pb->usbReqCount = 0;
- pb->usbClassType = kUSBDataClass; /* data class */
- pb->usbSubclass = 0; /* any subclass */
- pb->usbProtocol = 0; /* any protocol */
- pb->usb.cntl.WValue = 0; /* alt */
- if (sp->retries > 0)
- {
- sp->onError = kGetDataInterface;
- } else {
- sp->onError = kReset;
- }
-
- noteError("\pModem driver parsing the Data interface");
- if(immediateError(err = USBFindNextInterfaceDescriptorImmediate(pb)))
- { /* this should return immediately */
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- /* remember the current position */
- sp->interface = pb->usbBuffer;
- StatusMessage(sp->deviceRef, "\pData Interface Descriptor - ", (unsigned long)sp->interface);
-
- sp->interfaceOffset = pb->usbReqCount;
-
- /* Find the out endpoint */
- pb->usbFlags = kUSBOut;
- pb->usbClassType = kUSBBulk;
- pb->usbSubclass = 0; /* Find the first one */
-
- noteError("\pModem driver parsing the bulk out endpoint");
- if(immediateError(err = USBFindNextEndpointDescriptorImmediate(pb)))
- { /* this should return immediately */
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
-
- sp->deviceRef = pb->usbReference;
-
- pb->usbFlags = kUSBOut;
- /* The params are set up correctly so open it */
- //eDesc = pb->usbBuffer;
- //pb->usbValue = USBToHostWord(eDesc->maxPacketSize);
- // max packet size is now returned in usbValue
-
- noteError("\pModem driver opening bulk out pipe");
- if(immediateError(err = USBOpenPipe(pb)))
- {
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
-
- break;
-
- case kGetEndpoint:
- /* Out Endpoint is open */
-
- /* remember the ref */
- sp->bulkOut = pb->usbReference;
- StatusMessage(sp->deviceRef, "\pBulk Out Endpoint - ", sp->bulkOut);
-
- /* Find the in endpoint */
-
- /* restore the device ref, it gets overwritten by the open */
- pb->usbReference = sp->deviceRef;
-
- /* set search back to just found interface */
- pb->usbBuffer = sp->interface;
- pb->usbReqCount = sp->interfaceOffset;
-
- pb->usbFlags = kUSBIn;
- pb->usbClassType = kUSBBulk;
- pb->usbSubclass = 0; /* Find the first one */
- if (sp->retries > 0)
- {
- sp->onError = kGetEndpoint;
- } else {
- sp->onError = kReset;
- }
-
- noteError("\pModem driver parsing the bulk in endpoint");
- if(immediateError(err = USBFindNextEndpointDescriptorImmediate(pb)))
- { /* this should return immediatly */
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- pb->usbFlags = kUSBIn;
- /* The params are set up correctly so open it */
- eDesc = pb->usbBuffer;
- pb->usbProtocol = USBToHostWord(eDesc->maxPacketSize);
-
- noteError("\pModem driver opening bulk in pipe");
- if(immediateError(err = USBOpenPipe(pb)))
- {
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
-
- break;
-
- case kGetCommInterface:
- /* In Endpoint is open */
-
- /* remember the ref */
- sp->bulkIn = pb->usbReference;
- StatusMessage(sp->deviceRef, "\pBulk In Endpoint - ", sp->bulkIn);
-
- /* find the Comm Class interface */
- pb->usbBuffer = sp->conf; /* set it back to config desc. */
- pb->usbReqCount = 0;
- pb->usbFlags = 0;
- pb->usbClassType = kUSBCommClass; /* Comm class */
- pb->usbSubclass = 2; /* Abstract Control Model */
- pb->usbProtocol = 1; /* Hayes protocol */
- pb->usb.cntl.WValue = 0; /* alt */
- if (sp->retries > 0)
- {
- sp->onError = kGetCommInterface;
- } else {
- sp->onError = kReset;
- }
-
- noteError("\pModem driver parsing the Class interface");
- if(immediateError(err = USBFindNextInterfaceDescriptorImmediate(pb)))
- { /* this should return immediately */
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- /* remember the current position */
- sp->clinterface = pb->usbBuffer;
- StatusMessage(sp->deviceRef, "\pClass Interface Descriptor - ", (unsigned long)sp->clinterface);
-
- sp->clinterfaceOffset = pb->usbReqCount;
-
- /* Find the interrupt endpoint */
-
- /* restore the device ref, it gets overwritten by the open */
- pb->usbReference = sp->deviceRef;
-
- /* set search back to just found interface */
- pb->usbBuffer = sp->clinterface;
- pb->usbReqCount = sp->clinterfaceOffset;
-
- pb->usbFlags = kUSBIn;
- pb->usbClassType = kUSBInterrupt;
- pb->usbSubclass = 0; /* Find the first one */
- if (sp->retries > 0)
- {
- sp->onError = kGetCommInterface;
- } else {
- sp->onError = kReset;
- }
-
- noteError("\pModem Driver parsing the interrupt in endpoint");
- if(immediateError(err = USBFindNextEndpointDescriptorImmediate(pb)))
- { /* this should return immediatly */
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- pb->usbFlags = kUSBIn;
- /* The params are set up correctly so open it */
- eDesc = pb->usbBuffer;
- pb->usbProtocol = USBToHostWord(eDesc->maxPacketSize);
-
- noteError("\pModem Driver opening interrupt in pipe");
- if(immediateError(err = USBOpenPipe(pb)))
- {
- USBExpertFatalError(sp->deviceRef, err, sp->errorString, 0);
- }
-
- break;
-
- case kConfigDone:
- /* Interrupt is open */
-
- /* remember the ref */
- sp->interrupt = pb->usbReference;
- StatusMessage(sp->deviceRef, "\pInterrupt In Endpoint - ", sp->interrupt);
-
- StartStatusMonitor(sp->interrupt);
-
- // device is fully configured, ready for somebody to set the baud rate, etc.
- // and start reading/writing to the bulk endpoints
- syncPB.usbStatus = kAvailableStatus;
- StatusMessage(sp->deviceRef, "\pModem configuration complete.", 0);
- break;
-
- default:
- noteError("\pInternal Error unused case in Modem Configuration handler");
- StatusMessage(sp->deviceRef, sp->errorString, (pb->usbRefcon-1));
- break;
- }
- break; /* only execute once, unless continue used */
- }while(1); /* so case can be reentered with a continue */
- }
-
- UInt16 statusData[8];
-
- /************************************************************************************/
- //
- // ResetInterruptPB
- //
- // Re-initialize the interrupt PB.
- //
- /************************************************************************************/
-
- static void ResetInterruptPB(USBPB *pb)
- {
- pb->usbReqCount = 16;
- pb->usbBuffer = &statusData;
- pb->usbStatus = noErr;
- }
-
- UInt8 Intrretries = 0;
-
- /************************************************************************************/
- //
- // interruptCompletion
- //
- // Interrupt completion handler.
- //
- /************************************************************************************/
-
- static void interruptCompletion(USBPB *pb)
- {
- serPB *sp = &gSerialGlobals;
- OSStatus err;
- unsigned char newErrs = 0;
- ShimSerialGlobals *globals = gGlobals;
-
- TraceMessage(0, "\pEntering interruptCompletion");
-
- if (pb->usbStatus != kUSBAbortedError) // are we being asked to quit?
- {
- if (pb->usbStatus != noErr)
- {
- StatusMessage(sp->deviceRef, "\pModemDriver: interruptCompletion error ", pb->usbStatus);
- if (pb->usbStatus == kUSBEndpointStallErr)
- {
- ClearDevice();
- }
- USBClearPipeStallByReference(gSerialGlobals.interrupt);
-
- Intrretries++;
- if (Intrretries > 10)
- return; // we'll just give up for now
-
- DoDelay();
-
- } else {
- Intrretries = 0;
- TraceMessage(0, "\pInterrupt received");
- if ((pb->usbActCount > 2) && ((statusData[0] & 0x00FF) == kSerialState))
- {
- sp->modemUSBStatus = HostToUSBWord(statusData[4]);
-
- if (sp->modemUSBStatus & kUSBParityErr)
- newErrs |= parityErr;
- if (sp->modemUSBStatus & kUSBFramingErr)
- newErrs |= framingErr;
- if (sp->modemUSBStatus & kUSBHwOverRunErr)
- newErrs |= hwOverrunErr;
-
- globals->serStat.cumErrs |= newErrs;
- StatusMessage(sp->deviceRef, "\pModem Serial state - ", sp->modemUSBStatus);
- }
- }
-
- ResetInterruptPB(pb);
-
- if(immediateError(err = USBIntRead(pb)))
- {
- StatusMessage(sp->deviceRef, "\pCouldn't queue interrupt read!", err);
- }
- }
- }
-
- /************************************************************************************/
- //
- // StartStatusMonitor
- //
- // Kick off the interrupt mechanism.
- //
- /************************************************************************************/
-
- static void StartStatusMonitor(USBPipeRef interruptPipe)
- {
- USBPB *pb = &interruptPB;
- serPB *sp = &gSerialGlobals;
- OSStatus err;
-
- TraceMessage(0, "\pEntering StartStatusMonitor");
-
- InitializePB(pb, interruptPipe, interruptCompletion);
-
- ResetInterruptPB(pb);
-
- if(immediateError(err = USBIntRead(pb)))
- {
- StatusMessage(sp->deviceRef, "\pCouldn't start interrupt read!", err);
- }
-
- }
-
- /************************************************************************************/
- //
- // syncCompletion
- //
- // Completion handler for all sync (setup) requests.
- //
- /************************************************************************************/
-
- static void syncCompletion(USBPB *pb)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering syncCompletion");
-
- if (pb->usbStatus != noErr)
- {
- USBExpertFatalError(sp->deviceRef, pb->usbStatus, "\pModemDriver: syncCompletion err for bRequest", pb->usb.cntl.BRequest);
- if (pb->usbStatus == kUSBEndpointStallErr)
- {
- // ClearDevice();
- }
- USBClearPipeStallByReference(pb->usbReference);
- }
-
- pb->usbStatus = kAvailableStatus;
- }
-
- /************************************************************************************/
- //
- // TimeoutPrevRequest
- //
- // Timeout for all sync. requests.
- //
- /************************************************************************************/
-
- Boolean TimeoutPrevRequest(void)
- {
- USBPB *pb = &syncPB;
- serPB *sp = &gSerialGlobals;
- AbsoluteTime startTime;
- Duration elapsedTime;
-
- if (pb->usbStatus == kAvailableStatus)
- return false;
-
- startTime = UpTime();
-
- while (pb->usbStatus != kAvailableStatus){
- elapsedTime = AbsoluteDeltaToDuration(UpTime(), startTime);
- if (elapsedTime < 0) elapsedTime = elapsedTime/(-1000); // make sure it's in milliseconds
- if (elapsedTime > 100*durationMillisecond){
- StatusMessage(sp->deviceRef, "\pModem driver, device request timeout - aborting", 0);
- USBAbortPipeByReference(pb->usbReference);
- return true;
- }
- }
- return false;
- }
-
- /************************************************************************************/
- //
- // TimeoutStallRequest
- //
- // Timeout for all stall clear requests.
- //
- /************************************************************************************/
-
- Boolean TimeoutStallRequest(void)
- {
- USBPB *pb = &stallPB;
- serPB *sp = &gSerialGlobals;
- AbsoluteTime startTime;
- Duration elapsedTime;
-
- if (pb->usbStatus == kAvailableStatus)
- return false;
-
- startTime = UpTime();
-
- while (pb->usbStatus != kAvailableStatus){
- elapsedTime = AbsoluteDeltaToDuration(UpTime(), startTime);
- if (elapsedTime < 0) elapsedTime = elapsedTime/(-1000); // make sure it's in milliseconds
- if (elapsedTime > 100*durationMillisecond){
- StatusMessage(sp->deviceRef, "\pModem driver, Stall timeout - aborting", 0);
- USBAbortPipeByReference(pb->usbReference);
- return true;
- }
- }
- return false;
- }
-
- /************************************************************************************/
- //
- // TimeoutDelayRequest
- //
- // Timeout for delay requests.
- //
- /************************************************************************************/
-
- Boolean TimeoutDelayRequest(void)
- {
- USBPB *pb = &delayPB;
- serPB *sp = &gSerialGlobals;
- AbsoluteTime startTime;
- Duration elapsedTime;
-
- if (pb->usbStatus == kAvailableStatus)
- return false;
-
- startTime = UpTime();
-
- while (pb->usbStatus != kAvailableStatus){
- elapsedTime = AbsoluteDeltaToDuration(UpTime(), startTime);
- if (elapsedTime < 0) elapsedTime = elapsedTime/(-1000); // make sure it's in milliseconds
- if (elapsedTime > 100*durationMillisecond){
- return true;
- }
- }
- return false;
- }
-
- /************************************************************************************/
- //
- // USBSetBaudRate
- //
- // Set up and send SetLineCoding request for baud rate only.
- //
- /************************************************************************************/
-
- void USBSetBaudRate(UInt32 baudRate)
- {
- USBPB *pb = &syncPB;
- serPB *sp = &gSerialGlobals;
- OSStatus err;
- UInt16 temp = 0;
- UInt16 rateh;
- Boolean setdte = false;
-
- TraceMessage(0, "\pEntering USBSetBaudRate");
-
- if (TimeoutPrevRequest())
- return;
-
- if (baudRate == kMaxBaudRate) // We're going to lock to max for the moment
- {
-
- // convert baudrate I hate Intel...
- temp = baudRate % 0x10000;
- rateh = USBToHostWord(temp);
- if (rateh != sp->Line_Settings.DTERate1)
- {
- sp->Line_Settings.DTERate1 = rateh;
- setdte = true;
- }
- temp = baudRate / 0x10000;
- rateh = USBToHostWord(temp);
- if (rateh != sp->Line_Settings.DTERate2)
- {
- sp->Line_Settings.DTERate2 = rateh;
- setdte = true;
- }
-
- // Only do it if it's changing
- if (setdte)
- {
- pb->usbStatus = noErr;
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);
- pb->usb.cntl.BRequest = kSetLineCoding;
- pb->usb.cntl.WValue = 0;
- pb->usb.cntl.WIndex = 1;
- pb->usbReqCount = sizeof(sp->Line_Settings)-1;
- pb->usbBuffer = &sp->Line_Settings;
-
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- StatusMessage(sp->deviceRef, "\pModem driver Setting baud rate", err);
- pb->usbStatus = kAvailableStatus;
- }
- }
- }
- }
-
- /************************************************************************************/
- //
- // USBSetLineCoding
- //
- // Set up and send SetLineCoding Request for all settings.
- //
- /************************************************************************************/
-
- void USBSetLineCoding(LineParms Line_Coding)
- {
- USBPB *pb = &syncPB;
- serPB *sp = &gSerialGlobals;
- OSStatus err;
- Boolean setcoding = false;
-
- TraceMessage(0, "\pEntering USBSetLineCoding");
-
- if (TimeoutPrevRequest())
- return;
-
- // save the settings only if they've changed
- if (Line_Coding.CharFormat != sp->Line_Settings.CharFormat)
- {
- sp->Line_Settings.CharFormat = Line_Coding.CharFormat;
- setcoding = true;
- }
- if (Line_Coding.ParityType != sp->Line_Settings.ParityType)
- {
- sp->Line_Settings.ParityType = Line_Coding.ParityType;
- setcoding = true;
- }
- if (Line_Coding.DataBits != sp->Line_Settings.DataBits)
- {
- sp->Line_Settings.DataBits = Line_Coding.DataBits;
- setcoding = true;
- }
-
- // Don't do this if they haven't changed
- if (setcoding)
- {
- pb->usbStatus = noErr;
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);
- pb->usb.cntl.BRequest = kSetLineCoding;
- pb->usb.cntl.WValue = 0;
- pb->usb.cntl.WIndex = 1;
- pb->usbReqCount = sizeof(sp->Line_Settings)-1;
- pb->usbBuffer = &sp->Line_Settings;
-
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- StatusMessage(sp->deviceRef, "\pModem driver Setting Line Coding", err);
- pb->usbStatus = kAvailableStatus;
- }
- }
- }
-
- /************************************************************************************/
- //
- // USBSetControlLineState
- //
- // Set up and send SetControlLineState (DTR and RTS).
- //
- /************************************************************************************/
-
- void USBSetControlLineState(void)
- {
- USBPB *pb = &syncPB;
- serPB *sp = &gSerialGlobals;
- OSStatus err;
-
- TraceMessage(0, "\pEntering USBSetControlLineState");
-
- if (TimeoutPrevRequest())
- return;
-
- pb->usbStatus = noErr;
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);
- pb->usb.cntl.BRequest = kSetControlLineState;
- pb->usb.cntl.WValue = USBToHostWord(sp->lineState);
- pb->usb.cntl.WIndex = 1;
- pb->usbReqCount = 0;
- pb->usbBuffer = 0;
-
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- StatusMessage(sp->deviceRef, "\pModem driver Setting Control Line State", err);
- pb->usbStatus = kAvailableStatus;
- }
- }
-
- /************************************************************************************/
- //
- // USBSetDTRState
- //
- // Set the DTR state.
- //
- /************************************************************************************/
-
- void USBSetDTRState(Boolean state)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering USBSetDTRState");
-
- if (state)
- {
- sp->lineState |= kDTROn;
- } else {
- if (!sp->DTRClose)
- sp->lineState &= (kDTROff + kRTSOn);
- }
- }
-
- /************************************************************************************/
- //
- // USBSetRTSState
- //
- // Set the RTS state.
- //
- /************************************************************************************/
-
- void USBSetRTSState(Boolean state)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering USBSetRTSState");
-
- if (state)
- {
- sp->lineState |= kRTSOn;
- } else {
- sp->lineState &= (kRTSOff + kDTROn);
- }
- }
-
- /************************************************************************************/
- //
- // USBSendBreak
- //
- // Set up and send break request.
- //
- /************************************************************************************/
-
- void USBSendBreak(Boolean state)
- {
- USBPB *pb = &syncPB;
- serPB *sp = &gSerialGlobals;
- OSStatus err;
-
- TraceMessage(0, "\pEntering USBSendBreak");
-
- if (TimeoutPrevRequest())
- return;
-
- pb->usbStatus = noErr;
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);
- pb->usb.cntl.BRequest = kSendBreak;
- if (state)
- {
- pb->usb.cntl.WValue = kBreakOn;
- }
- else
- {
- pb->usb.cntl.WValue = kBreakOff;
- }
- pb->usb.cntl.WIndex = 1;
- pb->usbReqCount = 0;
- pb->usbBuffer = 0;
-
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- StatusMessage(sp->deviceRef, "\pModem driver Setting Break State", err);
- pb->usbStatus = kAvailableStatus;
- }
- }
-
- /************************************************************************************/
- //
- // USBSetCloseDTR
- //
- // Set the state of DTR on close.
- //
- /************************************************************************************/
-
- void USBSetCloseDTR(void)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering USBSetCloseDTR");
-
- sp->DTRClose = true;
- }
-
- /************************************************************************************/
- //
- // USBGetDCDValue
- //
- // Gets the current state of CD.
- //
- /************************************************************************************/
-
- UInt8 USBGetDCDValue(void)
- {
- serPB *sp = &gSerialGlobals;
- UInt8 dcd = 0;
-
- TraceMessage(0, "\pEntering USBGetDCDValue");
-
- if (sp->modemUSBStatus & kUSBDCD)
- dcd = 1;
-
- return dcd;
- }
-
- /************************************************************************************/
- //
- // ModemDriverEntry
- //
- // Initializes and starts the whole show.
- //
- /************************************************************************************/
-
- void modemDriverEntry(USBDeviceRef device, USBDeviceDescriptor *desc)
- {
- static Boolean beenThereDoneThat = false;
- static USBDeviceDescriptor ourDeviceDescriptor;
-
- DebugMessage("\pEntering modemDriverEntry - Sync. point");
-
- if(beenThereDoneThat)
- {
- StatusMessage(device, "\pModem driver called second time", 0);
- return;
- }
- beenThereDoneThat = true;
-
- ourDeviceDescriptor = *desc;
- gSerialGlobals.deviceDescriptor = &ourDeviceDescriptor;
- gSerialGlobals.deviceRef = device;
-
- InitializePB(&syncPB, device, syncCompletion);
- InitializePB(&stallPB, device, stallHandler);
- stallPB.usbStatus = kAvailableStatus;
- InitializePB(&delayPB, device, delayHandler);
- delayPB.usbStatus = kAvailableStatus;
-
- InitializePB(&gSerialGlobals.pb, device, ConfigurationHandler);
- gSerialGlobals.pb.usbRefcon = 1;
- gSerialGlobals.pb.usbBuffer = nil;
-
- gSerialGlobals.retries = 10; // Let's keep it reasonable for now
-
- ConfigurationHandler(&gSerialGlobals.pb);
- }
-
- /************************************************************************************/
- //
- // InitializePB
- //
- // Initial a parameter block.
- //
- /************************************************************************************/
-
- static void InitializePB(USBPB *pb, USBDeviceRef ref, USBCompletion handler)
- {
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->pbLength = sizeof(*pb);
- pb->usbReference = ref;
- pb->usbCompletion = handler;
- pb->usbStatus = noErr;
-
- }
-
- static errCount, readActive = false;
-
- /************************************************************************************/
- //
- // readCompletion
- //
- // Completion handler for USB reads.
- //
- /************************************************************************************/
-
- void readCompletion(USBPB *pb)
- {
-
- TraceMessage(0,"\pEntering readCompletion");
-
- readActive = false;
-
- if (pb->usbStatus != kUSBAbortedError) // are we being asked to quit?
- {
- if (pb->usbStatus == noErr){
- LogData(kUSBIn, pb->usbActCount, pb->usbBuffer);
- HAL_ShimInput(pb->usbBuffer, pb->usbActCount);
- }else{
- if ((pb->usbStatus != kUSBUnderRunErr) && errCount++ < 10)
- StatusMessage(gSerialGlobals.deviceRef, "\pRead completion error ", pb->usbStatus);
-
- if (pb->usbStatus == kUSBEndpointStallErr)
- {
- // ClearDevice();
- }
- USBClearPipeStallByReference(gSerialGlobals.bulkIn);
- if (pb->usbActCount > 0)
- HAL_ShimInput(pb->usbBuffer, pb->usbActCount);
- }
-
- USBStartReadPolling();
- }
- }
-
- static UInt8 ioBuffer[64];
-
- /************************************************************************************/
- //
- // USBStartReadPolling
- //
- // Start the USB read mechanism.
- //
- /************************************************************************************/
-
- void USBStartReadPolling(void)
- {
- OSStatus status;
-
- TraceMessage(0,"\pEntering USBStartReadPolling");
-
- if (gSerialGlobals.bulkIn && !readActive){
- InitializePB(&readPB, gSerialGlobals.bulkIn, readCompletion);
- readPB.usbBuffer = ioBuffer;
- readPB.usbReqCount = sizeof(ioBuffer);
- if(immediateError(status = USBBulkRead(&readPB)))
- {
- USBExpertFatalError(gSerialGlobals.deviceRef, status, "\pModemDriver: Couldn't start read polling", 0);
- return;
- }
- readActive = true;
- }
- }
-
- /************************************************************************************/
- //
- // USBStopReadPolling
- //
- // You guessed it stop the USB read mechanism.
- //
- /************************************************************************************/
-
- void USBStopReadPolling()
- {
- StatusMessage(gSerialGlobals.deviceRef, "\pAborting Bulk-in pipe", 0);
-
- if (gSerialGlobals.bulkIn){
- USBAbortPipeByReference(gSerialGlobals.bulkIn);
- }
- }
-
- static UInt32 writeActive;
-
- /************************************************************************************/
- //
- // writeCompletion
- //
- // USB write completion handler.
- //
- /************************************************************************************/
-
- void writeCompletion(USBPB *pb)
- {
- IOParam *iopb;
-
- TraceMessage(0, "\pEntering writeCompletion");
-
- if (pb->usbStatus != kUSBAbortedError) // are we being asked to quit?
- {
- if (pb->usbStatus != noErr)
- {
- StatusMessage(gSerialGlobals.deviceRef, "\pWrite Failed", pb->usbStatus);
-
- if (pb->usbStatus == kUSBEndpointStallErr)
- {
- // ClearDevice();
- }
- USBClearPipeStallByReference(pb->usbReference);
- }
- }
- writeActive--;
- gGlobals->pbOut = nil;
- iopb = (IOParam *)pb->usbRefcon;
- iopb->ioActCount = pb->usbActCount;
-
- ShimIOComplete((union ParamBlockRec *)iopb, pb->usbStatus ? ioErr : 0);
-
- }
-
- /************************************************************************************/
- //
- // USBSerialWrite
- //
- // USB serial write routine.
- //
- /************************************************************************************/
-
- OSStatus USBSerialWrite(IOParam *pb)
- {
- OSStatus status = noErr;
-
- TraceMessage(0, "\pEntering USBSerialWrite");
-
- if (writeActive){
- StatusMessage(gSerialGlobals.deviceRef, "\pOverlapping writes!", writePB.usbStatus);
- status = ioErr;
- } else if (gSerialGlobals.bulkOut){
-
- InitializePB(&writePB, gSerialGlobals.bulkOut, writeCompletion);
- writePB.usbRefcon = (UInt32)pb;
- writePB.usbBuffer = pb->ioBuffer;
- writePB.usbReqCount = pb->ioReqCount;
-
- LogData(kUSBOut, writePB.usbReqCount, writePB.usbBuffer);
-
- if(immediateError(status = USBBulkWrite(&writePB)))
- {
- StatusMessage(gSerialGlobals.deviceRef, "\pModemDriver: Couldn't start write", status);
- } else {
- writeActive++;
- status = 1; // pending
- }
- } else {
- status = ioErr;
- }
- return status;
- }
-
- /************************************************************************************/
- //
- // KillUSBIO
- //
- // Kill all USB io operations in progress.
- //
- /************************************************************************************/
-
- void KillUSBIO(void)
- {
- IOParam *pb;
- ShimSerialGlobals *globals = gGlobals;
-
- StatusMessage(gSerialGlobals.deviceRef, "\pModem: Killing all USB IO", 0);
-
- if (gSerialGlobals.bulkIn){
- USBAbortPipeByReference(gSerialGlobals.bulkIn);
- gSerialGlobals.bulkIn = nil;
- }
- if (gSerialGlobals.bulkOut){
- USBAbortPipeByReference(gSerialGlobals.bulkOut);
- gSerialGlobals.bulkOut = nil;
- }
- if (gSerialGlobals.interrupt){
- USBAbortPipeByReference(gSerialGlobals.interrupt);
- gSerialGlobals.interrupt = nil;
- }
-
- pb = (IOParam *)globals->pbIn;
- if (pb) {
- ShimIOComplete((union ParamBlockRec *)pb, ioErr);
- globals->pbIn = nil;
- }
- pb = (IOParam *)globals->pbOut;
- if (pb) {
- ShimIOComplete((union ParamBlockRec *)pb, ioErr);
- globals->pbOut = nil;
- }
- }
-
- /************************************************************************************/
- //
- // InitLineCoding
- //
- // Store the initial line settings.
- //
- /************************************************************************************/
-
- void InitLineCoding(LineParms Line_Coding)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering InitLineCoding");
-
- // save the settings
- sp->Line_Settings.DTERate1 = Line_Coding.DTERate1;
- sp->Line_Settings.DTERate2 = Line_Coding.DTERate2;
- sp->Line_Settings.CharFormat = Line_Coding.CharFormat;
- sp->Line_Settings.ParityType = Line_Coding.ParityType;
- sp->Line_Settings.DataBits = Line_Coding.DataBits;
- }
-
- /************************************************************************************/
- //
- // DoDelay
- //
- // Set up to do a USB delay.
- //
- /************************************************************************************/
-
- void DoDelay(void)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering DoDelay");
-
- if (TimeoutDelayRequest())
- return;
-
- delayPB.usbStatus = noErr;
- delayPB.usbReference = sp->deviceRef;
- delayPB.usbRefcon = 1;
- delayPB.usbReqCount = 5; // ~5ms (actually 5 frames at 1ms each)
- USBDelay(&delayPB);
- }
-
- /************************************************************************************/
- //
- // delayHandler
- //
- // Completion handler for USB delay.
- //
- /************************************************************************************/
-
- static void delayHandler(USBPB *pb)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering delayHandler");
-
- if (pb->usbStatus != noErr)
- StatusMessage(sp->deviceRef, "\pModemDriver: Delay fail?", pb->usbStatus);
-
- pb->usbStatus = kAvailableStatus;
- }
-
- /************************************************************************************/
- //
- // ClearDevice
- //
- // Set up and send ClearFeature request (for stall).
- //
- /************************************************************************************/
-
- void ClearDevice(void)
- {
- serPB *sp = &gSerialGlobals;
-
- TraceMessage(0, "\pEntering ClearDevice");
-
- if (TimeoutStallRequest())
- return;
-
- stallPB.usbStatus = noErr;
- stallPB.usbReference = sp->deviceRef;
- stallPB.usbRefcon = 1;
- stallHandler(&stallPB);
- }
-
- /************************************************************************************/
- //
- // stallHandler
- //
- // Completion handler for clear device/stall.
- //
- /************************************************************************************/
-
- static void stallHandler(USBPB *pb)
- {
- serPB *sp = &gSerialGlobals;
- OSStatus err = 0;
-
- TraceMessage(0, "\pEntering StallHandler");
-
- if (pb->usbStatus != noErr)
- {
- USBExpertFatalError(sp->deviceRef, pb->usbStatus, "\pModemDriver: Stall fail?", pb->usbRefcon);
- return;
- }
-
- // May have to do more here (like find out which endpoint is stalled) which is why an FSM is used
- // For the moment it's the Comm Class endpoint 0 which we'll try to clear (interupptComplete only for now)
- do{switch(pb->usbRefcon++)
- {
- case kEndpointStall:
- pb->usbStatus = noErr;
- pb->usbReference = sp->deviceRef;
- pb->pbVersion = kUSBCurrentPBVersion;
- pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
-
- pb->usb.cntl.BRequest = kUSBRqClearFeature;
- pb->usb.cntl.WValue = 0; // Endpoint stall
- pb->usb.cntl.WIndex = 0;
- pb->usbReqCount = 0;
- pb->usbBuffer = nil;
-
- if(immediateError(err = USBDeviceRequest(pb)))
- {
- StatusMessage(sp->deviceRef, "\pModem driver clearing device stall error", err);
- }
- break;
-
- case kStallDone:
- // stall should now be cleared
- if (pb->usbStatus != noErr)
- USBExpertFatalError(sp->deviceRef, pb->usbStatus, "\pModemDriver: stall handler err for bRequest", pb->usb.cntl.BRequest);
-
- pb->usbStatus = kAvailableStatus;
- break;
-
- default:
- StatusMessage(sp->deviceRef, "\pInternal Error unused case in stall handler", (pb->usbRefcon-1));
- break;
- }
- break; /* only execute once, unless continue used */
- }while(1); /* so case can be reentered with a continue */
- }
-
- #if ((DebugOn > 0) && (LogOn > 0))
-
- /************************************************************************************/
- //
- // Asciify
- //
- // Convert to Ascii character
- //
- /************************************************************************************/
-
- UInt8 Asciify(UInt8 i)
- {
-
- i &= 0xF;
- if ( i < 10 )
- return( '0' + i );
- else return( 55 + i );
-
- }
-
- #define dumplen 16 // Set this to the number of bytes to dump and the rest should work out correct
-
- #define buflen ((dumplen*2)+dumplen)+3
- #define Asciistart (dumplen*2)+3
-
- /************************************************************************************/
- //
- // USBLogData
- //
- // Dumps the requested amount of data to the USB Expert log.
- //
- /************************************************************************************/
-
- void USBLogData(UInt8 Dir, UInt32 Count, UInt8 *buf)
- {
- UInt8 wlen, i, Aspnt, Hxpnt;
- UInt8 wchr;
- UInt8 LocBuf[buflen];
-
- for ( i=1; i<=buflen; i++)
- {
- LocBuf[i] = 0x20;
- }
-
- if (Dir == kUSBIn)
- {
- TraceMessage(1, "\pRead Complete");
- } else {
- TraceMessage(1, "\pWrite");
- }
-
- if (Count > dumplen)
- {
- wlen = dumplen;
- } else {
- wlen = Count;
- }
-
- if (wlen > 0)
- {
- Aspnt = Asciistart;
- Hxpnt = 1;
- for (i=1; i<=wlen; i++)
- {
- wchr = buf[i-1];
- LocBuf[Hxpnt++] = Asciify(wchr >> 4);
- LocBuf[Hxpnt++] = Asciify(wchr);
- if ((wchr < 0x20) || (wchr == 0x7F)) // Non printable characters
- {
- LocBuf[Aspnt++] = 0x2E; // Replace with a period
- } else {
- LocBuf[Aspnt++] = wchr;
- }
- }
- LocBuf[0] = (wlen + Asciistart) + 1;
- TraceMessage(1, LocBuf);
- } else {
- TraceMessage(1, "\pNo data - Actual count=0");
- }
- }
- #endif